#pragma once
#include "base/core/com_define.h"

template<typename TYPE = int>
class Point2 
{
public:
	TYPE x, y;

public:
     inline Point2() 
	 {
		x = 0;
		y = 0;
	 }

     inline Point2(const TYPE ValueX, const TYPE ValueY)
		 :x(ValueX), y(ValueY) {}

     inline explicit Point2(const TYPE Value)
		 :x(Value), y(Value) {}

     inline explicit Point2(const TYPE Vec[2])
		 :x(Vec[0]), y(Vec[1]) {}

     inline explicit Point2(TYPE* const r)
		 :x(r[0]), y(r[1]) {}

	 inline TYPE operator[] (const size_t i) const 
	 {
		MMO_ASSERT(i < 2);
		return *(&x+i);
	 }

	 inline TYPE& operator[] (const size_t i) 
	 {
		MMO_ASSERT(i < 2);
		return *(&x+i);
	 }

	 inline Point2& operator = (const Point2& Value) 
	 {
		x = Value.x;
		y = Value.y;
		return (*this);
	 }

	 inline Point2& operator = (const TYPE Value) 
	 {
		x = Value;
		y = Value;
		return (*this);
	 }

	 inline bool operator == (const Point2& Value) const 
	 {
		 return (x == Value.x && y == Value.y);
	 }

	 inline bool operator != (const Point2& Value) const 
	 {
		 return (x != Value.x || y != Value.y);
	 }

	 inline Point2 operator + (const Point2& Value) const 
	 {
		 return Point2((x + Value.x), (y + Value.y));
	 }

	 inline Point2 operator - (const Point2& Value) const 
	 {
		 return Point2((x - Value.x), (y - Value.y));
	 }

	 inline Point2 operator * (const TYPE Value) const 
	 {
		 return Point2((x * Value), (y * Value));
	 }

	 inline Point2 operator * (const Point2& Value) const 
	 {
		 return Point2((x * Value.x), (y * Value.y));
	 }

	 inline Point2 operator / (const TYPE Value) const 
	 {
		 MMO_ASSERT(Value != 0);
		 return Point2((x / Value), (y / Value));
	 }

	 inline Point2 operator / (const Point2& Value) const 
	 {
		 MMO_ASSERT(Value.x != 0 && Value.y != 0);
		 return Point2((x / Value.x), (y / Value.y));
	 }

	 inline const Point2& operator + () const 
	 {
		 return (*this);
	 }

	 inline Point2 operator - () const 
	 {
		 return Point2(-x, -y);
	 }

	 inline friend Point2 operator * (const TYPE Value, const Point2& point) 
	 {
		 return Point2((Value * point.x), (Value * point.y));
	 }

	 inline friend Point2 operator / (const TYPE Value, const Point2& point) 
	 {
		MMO_ASSERT(point.x != 0 && point.y != 0);
		return Point2((Value / point.x), (Value / point.y));
	 }

	 inline friend Point2 operator + (const Point2& Value, const TYPE point) 
	 {
		 return Point2((point.x + Value), (point.y + Value));
	 }

	 inline friend Point2 operator + (const TYPE Value, const Point2& point) 
	 {
		 return Point2((Value + point.x), (Value + point.y));
	 }

	 inline friend Point2 operator - (const Point2& Value, const TYPE point) 
	 {
		 return Point2((point.x - Value), (point.y - Value));
	 }

	 inline friend Point2 operator - (const TYPE Value, const Point2& point) 
	 {
		 return Point2((Value - point.x), (Value - point.y));
	 }

	 inline friend Point2 AbsSub(const Point2& Value1, const Point2& Value2) {
		 return Point2(abs(Value2.x - Value1.x), abs(Value2.y - Value1.y));
	 }

	 inline friend float Slope(const Point2& Value1, const Point2& Value2) 
	 {
		 return ((float)(Value2.y - Value1.y) / (float)(Value2.x - Value1.x));
	 }

	 inline Point2& operator += (const Point2& Value) 
	 {
		x += Value.x;
		y += Value.y;
		return (*this);
	 }

	 inline Point2& operator += (const TYPE Value) 
	 {
		x += Value;
		y += Value;
		return (*this);
	 }

	 inline Point2& operator -= (const Point2& Value) 
	 {
		x -= Value.x;
		y -= Value.y;
		return (*this);
	 }

	inline Point2& operator -= (const TYPE Value) 
	{
		x -= Value;
		y -= Value;
		return (*this);
	}

	inline Point2& operator *= (const TYPE Value) 
	{
		x *= Value;
		y *= Value;
		return (*this);
	}

	inline Point2& operator *= (const Point2& Value) 
	{
		x *= Value.x;
		y *= Value.y;
		return (*this);
	}

	inline Point2& operator /= (const TYPE Value) 
	{
		MMO_ASSERT(Value != 0.0f);
		TYPE tempValue = 1.0f / Value;
		x *= tempValue;
		y *= tempValue;
		return (*this);
	}
	
	inline Point2& operator /= (const Point2& Value) 
	{
		MMO_ASSERT((Value.x != 0) && (Value.y != 0));
		x /= Value.x;
		y /= Value.y;
		return (*this);
	}
};
